package Cluedo.GUI2;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Vector;

import javax.swing.ButtonGroup;
import javax.swing.ComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import Cluedo.API.CardImage;
import Cluedo.API.CluedoConfig;
import Cluedo.API.Constants;
import Cluedo.API.LanguagePack;
import Cluedo.API.StringFuncs;
import Cluedo.Game.Board;
import Cluedo.Game.Card;
import Cluedo.Game.CardCollection;
import Cluedo.Game.Player;

/**
 * 
 * Class handles entry and validation of new players
 * 
 * @author Alex
 */
public class PlayerSelect extends JPanel {
	int charModelIndex = 0;
	Vector charModelItems = new Vector();
    Player currentPlayer = new Player();
	CluedoConfig gameConfig = new CluedoConfig();

    private static final String DEFAULT_GROUP = "setup_game";	

	JTextField nameText = new JTextField();
	JList playerList = new JList();
	JComboBox characterList = new JComboBox();
	ButtonGroup playerTypesGroup = new ButtonGroup();
    
	JRadioButton humanOption = new JRadioButton(LanguagePack.getString("human_player", DEFAULT_GROUP));
	JRadioButton aiNormalOption = new JRadioButton(LanguagePack.getString("normal_ai_player", DEFAULT_GROUP));
	JRadioButton aiHardOption = new JRadioButton(LanguagePack.getString("skilled_ai_player", DEFAULT_GROUP));
	JRadioButton customAIOption1 = new JRadioButton("Custom 1");
	JRadioButton customAIOption2 = new JRadioButton("Custom 2");
	JRadioButton customAIOption3 = new JRadioButton("Custom 3");
	CardImage cardPreview = null;

	JButton addPlayerButton;
	
	private void updateCharacterList() {
		System.out.println("updateCharacterList() "+((String) characterList.getSelectedItem()).toLowerCase());
		cardPreview.changeCard(new ImageIcon("./Resources/Cards/"
				+ ((String) characterList.getSelectedItem()).toLowerCase()
				+ ".gif"), ((String) characterList.getSelectedItem())
				.toLowerCase());
		repaint();
	}
	
	private ActionListener configButtonListener = new ActionListener() {

		public void actionPerformed(ActionEvent e) {
			boolean updateRequired = false;

			if (e.getActionCommand().equals("add_player")) {
				// Don't add blank players!
				if(nameText.getText().equals(""))
					return;
				
				String error = "";
				String cant_add_player_error = "Can't add player";

				// max name to be size 12
				if(nameText.getText().length() > Constants.MAX_PLAYER_NAME_LENGTH) {
				    String name_too_long_error = Constants.HTML_ON+ "The name chosen is too long<br>";
				    
				    error += name_too_long_error;
				    
				}
				// name must be alpha numeric
				if(StringFuncs.validAlphaNumeric(nameText.getText()) == false) {
				    String name_not_valid_error = "The name chosen may only contain letters and numbers<br>";
				    if(error.equals(""))
				        error = Constants.HTML_ON+ name_not_valid_error;
				    else
				        error+=  name_not_valid_error;
				    
				}
				if(!error.equals("")) {
				    JOptionPane.showMessageDialog(null, error, cant_add_player_error, JOptionPane.INFORMATION_MESSAGE);
				    return;
				}

				System.out.println("nameText: " + nameText.getText());
				if (gameConfig.playerExists(nameText.getText()) == false) {
					currentPlayer = new Player();

					String realName = nameText.getText();
					currentPlayer.setName(realName);
					currentPlayer.setCharacter((String) characterList
							.getSelectedItem());

					int type = 0;
					if (humanOption.isSelected() == true)
						type = 0;
					else if (aiNormalOption.isSelected() == true)
						type = 1;
					else if (aiHardOption.isSelected() == true)
						type = 2;
					else if (customAIOption1.isSelected() == true)
						type = 3;
					else if (customAIOption2.isSelected() == true)
						type = 4;
					else if (customAIOption3.isSelected() == true)
						type = 5;

					currentPlayer.setPlayerType(type);

					gameConfig.addPlayer(currentPlayer);
					currentPlayer = new Player();
					updateRequired = true;
					charModelIndex=0;
					nameText.setText("");
					aiNormalOption.setSelected(true);
					
					if(gameConfig.getPlayers().size() == Board.MAX_PLAYERS)
					    addPlayerButton.setEnabled(false);

				}

			} else if (e.getActionCommand().equals("change_player")) {

				updateRequired = true;
			} else if (e.getActionCommand().equals("remove_player")) {
				gameConfig.removePlayer(nameText.getText());
				updateRequired = true;
				if(gameConfig.getPlayers().size() < 6)
				    addPlayerButton.setEnabled(true);
			}

			if (updateRequired == true) {
				updatePlayerSelectLists();

			}
		}

	};
	
	KeyListener characterKeyListener = new KeyListener() {

		public void keyPressed(KeyEvent arg0) {	
		}

		public void keyReleased(KeyEvent arg0) {
			updateCharacterList();		
		}

		public void keyTyped(KeyEvent arg0) {
		}
		
	};
	
	ActionListener characterChangeListener = new ActionListener() {
		public void actionPerformed(ActionEvent e) {
			updateCharacterList();
		}
	};
	


	ListSelectionListener playerSelectionListener = new ListSelectionListener() {
		public void valueChanged(ListSelectionEvent arg0) {
			currentPlayer = gameConfig.getPlayer(((String) playerList
					.getSelectedValue()));

			if (currentPlayer != null) {
				cardPreview.changeCard(new ImageIcon("./Resources/Cards/"
						+ currentPlayer.getCharacter().toLowerCase() + ".gif"),
						currentPlayer.getCharacter().toLowerCase());
				cardPreview.repaint();
				nameText.setText(currentPlayer.getRealName());
				int type = currentPlayer.getPlayerType();
				if (type == 0)
					humanOption.setSelected(true);
				else if (type == 1)
					aiNormalOption.setSelected(true);
				else if (type == 2)
					aiHardOption.setSelected(true);
				else if (type == 3)
					customAIOption1.setSelected(true);
				else if (type == 4)
					customAIOption2.setSelected(true);
				else if (type == 5)
					customAIOption3.setSelected(true);
				

				characterList.setSelectedItem(currentPlayer.getCharacter());
				characterList.repaint();
				
			}
			System.out.println("Editing: " + currentPlayer);
		}

	};

	ComboBoxModel charModel = new ComboBoxModel() {
		public void updateMe() {
			if (currentPlayer != null
					&& !currentPlayer.getRealName().equals(""))
				charModelItems = gameConfig.getValidCharacterNames(currentPlayer
						.getCharacter());
			else
				charModelItems = gameConfig.getValidCharacterNames();
		}

		public Object getSelectedItem() {
			updateMe();
			if (charModelItems.size() == 0)
				return "";
			//if (charModelItems.elementAt(sel) == null)
			//	return charModelItems.elementAt(sel - 1);
			return charModelItems.elementAt(charModelIndex);
		}

		public void setSelectedItem(Object arg0) {
			updateMe();
			charModelIndex = 0;

			for (int i = 0; i < charModelItems.size(); i++)
				if (((String) charModelItems.elementAt(i)).equals(((String) arg0))) {
					charModelIndex = i;
					break;
				}
		}

		public int getSize() {
			updateMe();
			return charModelItems.size();
		}

		public Object getElementAt(int arg0) {
			updateMe();
			return charModelItems.elementAt(arg0);
		}

		public void addListDataListener(ListDataListener arg0) {
			

		}

		public void removeListDataListener(ListDataListener arg0) {
			

		}

	};

	private void updatePlayerSelectLists() {
		playerList.setListData(gameConfig.getPlayerNames());

		if (currentPlayer != null && !currentPlayer.getRealName().equals("")) {
			charModel.setSelectedItem(currentPlayer.getCharacter());
			System.out.println("In change mode");
		}
		else {
			charModelIndex = 0;
		}

		updateCharacterList();
		characterList.repaint();
	}

	public PlayerSelect(CluedoConfig gameConfig) {
		this.gameConfig=gameConfig;
	//	gameConfig.setCardSet("default");
		//gameConfig.loadCards();
		characterList.setModel(charModel);
		
		characterList.addActionListener(characterChangeListener);
		
		playerTypesGroup.add(humanOption);
		playerTypesGroup.add(aiNormalOption);
		playerTypesGroup.add(aiHardOption);
		playerTypesGroup.add(customAIOption1);
		playerTypesGroup.add(customAIOption2);
		playerTypesGroup.add(customAIOption3);

		playerList
				.setToolTipText("Click on any player here to change his/her details.");
		playerList.addListSelectionListener(playerSelectionListener);

		humanOption.setToolTipText(LanguagePack.getString("human_info_player", DEFAULT_GROUP));
		aiNormalOption.setToolTipText(LanguagePack.getString("normal_ai_info_player", DEFAULT_GROUP));
		aiHardOption.setToolTipText(LanguagePack.getString("skilled_ai_info_player", DEFAULT_GROUP));
		customAIOption1.setToolTipText("This is the custom AI player 1 made by using Clueme Editor");
		customAIOption2.setToolTipText("This is the custom AI player 2 made by using Clueme Editor");
		customAIOption3.setToolTipText("This is the custom AI player 3 made by using Clueme Editor");
		nameText.setToolTipText(LanguagePack.getString("your_name_info_player", DEFAULT_GROUP));
		aiNormalOption.setSelected(true);

		add(drawItems(), BorderLayout.CENTER);

		cardPreview.changeCard(new ImageIcon("./Resources/Cards/"
				+ ((String) characterList.getSelectedItem()).toLowerCase()
				+ ".gif"), ((String) characterList.getSelectedItem())
				.toLowerCase());

	}

	private JPanel drawItems() {

		JPanel content = new JPanel();
		content.setLayout(new BorderLayout());
		JLabel caption = new JLabel(
		        addBreaks(LanguagePack.getString("choose_players_message", DEFAULT_GROUP)));
		caption.setFont(new Font("Arial", Font.BOLD, 12));
		JPanel selection = new JPanel();
		JPanel chooser = getChoosePanel();
		JPanel spacer = new JPanel();

		GridBagLayout grid = new GridBagLayout();
		GridBagConstraints c = new GridBagConstraints();
		selection.setLayout(grid);

		JScrollPane playerScroller = new JScrollPane(playerList);
		playerScroller.setPreferredSize(new Dimension(100, 150));

		c.gridy = 0;
		c.gridx = 0;
		c.weightx = 0;

		spacer.setBorder(new javax.swing.border.EtchedBorder());
		spacer.add(new JLabel("Selected players"), BorderLayout.NORTH);
		spacer.add(playerScroller, BorderLayout.CENTER);
		spacer.setPreferredSize(new Dimension(150, 250));
		grid.setConstraints(spacer, c);
		selection.add(spacer);

		c.gridx = 1;
		c.weightx = 0;

		chooser.setPreferredSize(new Dimension(300, 250));
		chooser.setBorder(new javax.swing.border.EtchedBorder());
		grid.setConstraints(chooser, c);
		selection.add(chooser);

		spacer = new JPanel();
		c.gridx = 2;
		c.weightx = 1;

		grid.setConstraints(spacer, c);
		selection.add(spacer);

		content.add(caption, BorderLayout.NORTH);

		content.add(selection, BorderLayout.SOUTH);

		return content;

	}

	private JPanel getChoosePanel() {
		JPanel content = new JPanel();
		JPanel preview = new JPanel();
		JPanel config = new JPanel();

		/*
		 *               
		 * Name             |----------|
		 * _________        |          |
		 * Character        |          |
		 * _________        |          |
		 *                  |          |
		 * () Human         |          |
		 * () AI (easy)     |          |
		 * () AI (hard)     |          |
		 *                  |__________|
		 * 
		 *  Add  Change Remove
		 */

		cardPreview = new CardImage("", "");
		preview.add(cardPreview);
		preview.setOpaque(true);
		preview.setPreferredSize(new Dimension(100, 200));
		preview.setBackground(Color.white);

		config.setPreferredSize(new Dimension(180, 200));
		config.setOpaque(true);

		config.setLayout(new GridLayout(8, 0));
		config.add(new JLabel("Name"));
		config.add(nameText);
		config.add(new JLabel("Character"));
		config.add(characterList);
		config.add(new JLabel("Type"));
		config.add(humanOption);
		config.add(aiNormalOption);
		config.add(aiHardOption);
		config.add(customAIOption1);
		config.add(customAIOption2);
		config.add(customAIOption3);

		JPanel buttonArray = new JPanel();
		buttonArray.setLayout(new FlowLayout());
		
		addPlayerButton = configButton(LanguagePack.getString("add_player",
                DEFAULT_GROUP), "add_player");
		buttonArray.add(addPlayerButton);
		JButton changeButton = configButton(LanguagePack.getString("change_player",
                DEFAULT_GROUP), "change_player");
		changeButton.setEnabled(false);
        buttonArray.add(changeButton);
        buttonArray.add(configButton(LanguagePack.getString("remove_player",
                DEFAULT_GROUP), "remove_player"));

		content.add(config, BorderLayout.WEST);
		content.add(preview, BorderLayout.EAST);
		content.add(buttonArray, BorderLayout.SOUTH);

		return content;
	}

	/**
	 * Called from the suspect selection, this removes players entered
	 * and updates the list boxes.
	 * 
	 */

	public void notifyNewSuspects() {
		charModelItems = gameConfig.getValidCharacterNames(currentPlayer.getCharacter());
		gameConfig.setPlayers(new ArrayList());
		updatePlayerSelectLists();
		characterList.repaint();
	}

	/**
	 * Constructive algorithm returns a new CardCollection with all
	 * non-suspect cards included in current set.
	 * @param newSuspects  -- a vector containing all suspects to add
	 * @param CardCollection  -- the currentCardSet fetched from the gameConfig
	 *
	 * Example cluedoConfig.setCards( setSuspectCards( vectorOfNewSuspects , cluedoConfig.getCards() ) );
	 *
	 * This code goes into your own class as a static method, NOT in the CluedoConfig class.
	 * 
	 */
	public static CardCollection updateCardSet(Vector newSuspects, CardCollection currentCardSet, String type) {
		
		// What we're adding to, and will return
		CardCollection newSet = new CardCollection();
		
		// Add new suspects first from Vector
		for (int i = 0; i < newSuspects.size(); i++) {
			newSet
			.insertCard(new Card((String) newSuspects.elementAt(i),
					type));
		}
		
		// then add all cards which aren't suspect cards	
		for (int i = 0; i < currentCardSet.countCards(); i++) {
			if (!currentCardSet.cardAt(i).getType().equals(type)) {
				newSet.insertCard(currentCardSet.cardAt(i));
			}
		}

		return newSet;
	}


	
	/**
	 * @param string
	 * @return
	 */
	private JButton configButton(String string, String function) {
		JButton button = new JButton(string);

		button.setActionCommand(function);
		button.addActionListener(configButtonListener);

		return button;
	}
	
	/**
	 * @param string
	 * @return
	 */
	private static String addBreaks(String string) {
		string = string.replaceAll("@@", "<br>");
		string = Cluedo.API.Constants.HTML_ON + string + Cluedo.API.Constants.HTML_OFF;
		return string;
	}
  
}